package com.justgame.project.service.system.service.impl;

import com.alibaba.nacos.common.utils.UuidUtils;
import com.justgame.mq.client.constant.SystemQueueConstant;
import com.justgame.mq.client.service.RabbitMqSendService;
import com.justgame.project.base.servcice.BasicServiceImpl;
import com.justgame.project.cloud.base.entity.StringEncrypt;
import com.justgame.project.cloud.base.entity.WeChatAuthResult;
import com.justgame.project.cloud.common.constant.Regex;
import com.justgame.project.cloud.common.exception.Exc;
import com.justgame.project.cloud.common.util.*;
import com.justgame.project.service.system.entity.SysUserAccount;
import com.justgame.project.service.system.entity.SysUserInfo;
import com.justgame.project.service.system.entity.SysUserSocialInfo;
import com.justgame.project.service.system.mapper.SysUserInfoMapper;
import com.justgame.project.service.system.service.ISysUserAccountService;
import com.justgame.project.service.system.service.ISysUserInfoService;
import com.justgame.project.service.system.service.ISysUserRoleMappingService;
import com.justgame.project.service.system.service.ISysUserSocialInfoService;
import com.justgame.project.service.system.vo.UserAuthorizationResult;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpStatus;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;

/**
 *
 * 用户信息表服务实现类
 *
 * @@tableName sys_user_info
 * @author Zwb
 */
@Slf4j
@Service
@Transactional
@RequiredArgsConstructor
public class SysUserInfoServiceImpl extends BasicServiceImpl<SysUserInfoMapper, SysUserInfo> implements ISysUserInfoService {
    private final RedisUtils redisUtils;
    private final ISysUserSocialInfoService sysUserSocialInfoService;
    private final ISysUserAccountService sysUserAccountService;
    private final RabbitMqSendService rabbitMqSendService;

    @Override
    @NonNull
    public UserAuthorizationResult loginByUserNameAndPassword(String userName, String password) {
        Optional<SysUserInfo> userInfoOpt = findByUserNameIsAndPasswordIs(userName,StringEncrypt.originBy(password));
        Assert.isTrue(userInfoOpt.isPresent(),"账号名或密码错误");
        return login(userInfoOpt.get());
    }

    @Override
    public UserAuthorizationResult loginByEmail(String eMail, String eMailCode) {
        Assert.isTrue(MailManager.checkMailCode(eMail,eMailCode),"邮箱验证码错误");
        Optional<SysUserInfo> userInfoOpt = findByEmailIs(eMail);
        Assert.isTrue(userInfoOpt.isPresent(),"邮箱登录失败");
        return login(userInfoOpt.get());
    }

    @Override
    public UserAuthorizationResult loginByPhoneNumber(String phoneNumber, String smsCode) {
        // TODO 没接入短信验证不支持此登陆方式
        Assert.isTrue(true,"暂不支持此登录方式");
        Optional<SysUserInfo> userInfoOpt = findByPhoneNumberIs(phoneNumber);
        Assert.isTrue(userInfoOpt.isPresent(),"手机号登录失败");
        return login(userInfoOpt.get());
    }

    @Override
    public UserAuthorizationResult loginByWx(WeChatAuthResult authResult) {
        Assert.hasLength(authResult.getOpenid(),"登录已失效，请重新登录");
        Optional<SysUserInfo> userInfoOpt = findByOpenIdIs(authResult.getOpenid());
        if (userInfoOpt.isEmpty()){
            throw new Exc(HttpStatus.NON_AUTHORITATIVE_INFORMATION);
        }
        return login(userInfoOpt.get());
    }

    public UserAuthorizationResult login(SysUserInfo userInfo){
        ShiroUtils.login(userInfo.getId());
        Optional<SysUserSocialInfo> userSocialInfoOpt = sysUserSocialInfoService.findByUserInfoIdIs(userInfo.getId());
        Optional<SysUserAccount> userAccountOpt = sysUserAccountService.findByUserInfoIdIs(userInfo.getId());
        rabbitMqSendService.sendMsg(SystemQueueConstant.SYSTEM_USER_LOGIN_QUEUE,userInfo);
        return UserAuthorizationResult.builder()
                .id(userInfo.getId())
                .avatar(userSocialInfoOpt.map(SysUserSocialInfo::getAvatar).orElse(""))
                .userName(userInfo.getUserName())
                .sex(userInfo.getSex())
                .role(userInfo.getRole())
                .status(userInfo.getStatus())
                .email(userInfo.getEmail())
                .phoneNumber(MaskUtils.phone(userInfo.getPhoneNumber()))
                .nickname(userSocialInfoOpt.map(SysUserSocialInfo::getNickname).orElse(""))
                .coin(userAccountOpt.map(SysUserAccount::getCoin).orElse(BigDecimal.ZERO))
                .integral(userAccountOpt.map(SysUserAccount::getIntegral).orElse(BigDecimal.ZERO))
                .rmb(userAccountOpt.map(SysUserAccount::getRmb).orElse(BigDecimal.ZERO))
                .build();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean changeEmail(SysUserInfo sysUserInfo, String email, String emailCode) {
        /* 获取用户id */
        Long userId = ShiroUtils.getUserIdElseThrow();

        MailManager.checkMailCode(email, emailCode);
        AssertKit.isZero(countByEmailIs(email),"该邮箱已被使用，无法绑定！");
        /* 先查询旧邮箱，通知该邮箱已换绑 */
        SysUserInfo userInfo = getById(userId);
        AssertKit.notNull(userInfo,"账户信息不存在，请重新登录。若依旧存在此问题请联系管理者！");
        /* 更新 */
        AssertKit.isTrue(updateByEmail(userInfo,email),"更新失败！");
        /* TODO 通知的过程需要改进，放到MQ中处理 */
        /* 通知双方 */
        if (StringUtils.isNotBlank(userInfo.getEmail())) {
            MailManager.AfterChangedEmail(email, TimeUtil.simpleDateNow());
        }
        MailManager.AfterChangedEmail(email, userInfo.getUserName());
        return true;
    }

    @Override
    public boolean logout(SysUserInfo userInfo, HttpServletRequest request) {
        ShiroUtils.logout();
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public UserAuthorizationResult wxRegister(@NonNull String phoneNumber,@NonNull WeChatAuthResult authResult) {
        Assert.isTrue(Regex.isPhone(phoneNumber),"手机号格式不正确");
        Assert.isTrue(countByPhoneNumberIs(phoneNumber) == 0,"该手机号已被绑定");
        Assert.isTrue(countByOpenIdIs(authResult.getOpenid()) == 0,"当前微信已绑定过手机号，请勿多次绑定");
        String randomUserName = UUID.randomUUID().toString().replaceAll("-","").substring(15);
        SysUserInfo userInfo = wechatUserRegister(
                randomUserName, /* 用户名 */
                StringEncrypt.originBy(randomUserName), /* 密码加密 */
                phoneNumber, /* 手机号 */
                authResult.getOpenid() /* openId */
        );
        sysUserSocialInfoService.addByUserRegister(RandomStringUtil.Nickname(),userInfo.getId());
        sysUserAccountService.addByUserRegister(userInfo.getId(),null,null);
        rabbitMqSendService.sendMsg(SystemQueueConstant.SYSTEM_USER_REGISTER,userInfo);
        return login(userInfo);
    }
}
